#include <iostream>
#include "MinMax.h"
#include "Gomoku.h"
#include "Board.h"

MinMax::MinMax(const unsigned char & _IAcolor)
: _IAcolor(_IAcolor)
{
}

MinMax::~MinMax() {}

int				MinMax::Min(int depth, BoardCase*** _area)
{
	if (depth == 0 || this->Winner())
		return (this->Eval((*_area)[1][1]));
	int	min = 42000;
	int	val = 0;
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			if (GET_COLOR((*_area)[i][j]) == COLOR_NONE)
			{
				(*_area)[i][j] = COLOR_BLACK;
				val = this->Max(depth - 1, _area);
				if (val < min) min = val;
				(*_area)[i][j] = COLOR_NONE;
			}
		}
	}
}
int				MinMax::Max(int depth, BoardCase*** _area)
{
	if (depth == 0 || this->Winner()) return (this->Eval((*_area)[1][1]));
	int	max = -42000;
	int	val = 0;
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			if (GET_COLOR((*_area)[i][j]) == COLOR_NONE)
			{
				(*_area)[i][j] = COLOR_WHITE;
				val = this->Min(depth - 1, _area);
				if (val > max) max = val;
				(*_area)[i][j] = COLOR_NONE;
			}
		}
	}
}

int MinMax::InspectArea(int _x, int _y, BoardCase& _center, int depth)
{
	depth--;
	int eval = 0;
	if (depth == 0)
		return (this->Eval(_center));
	BoardCase** cases = Gomoku::Instance().Board.Cases;
	// Init area
	BoardCase*** area;
	area = new BoardCase**[3];
	for (int i = 0, offy = -1; i < 3; i++, offy++)
	{
		area[i] = new BoardCase*[3];
		for (int j = 0, offx = -1; j < 3; j++, offx++)
		{
			if (_x + offx >= 0 && _x + offx < Board::WIDTH && _y + offy >= 0 && _y + offy < Board::HEIGHT)
				area[i][j] = &cases[_y + offy][_x + offx];
			else
				area[i][j] = NULL;
		}
	}

	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			if (area[i][j] != NULL)
			{
				if (GET_COLOR(*area[i][j]) == COLOR_NONE && i != 1 && j != 1)
				{
					int r = this->Max(depth, (BoardCase***)area);
					if (r > eval)
						eval = r;
				}
			}
		}
	}
	return (eval);
}

void			MinMax::IaPlay(int depth)
{
	BoardCase** cases = Gomoku::Instance().Board.Cases;

	for (int i = 0; i < Board::HEIGHT; i++)
	{
		for (int j = 0; j < Board::WIDTH; j++)
		{
			if (GET_COLOR(cases[i][j]) != COLOR_NONE)
				this->InspectArea(j, i, cases[i][j], depth);
		}
	}
}

static int		countAlignedAlly(BoardCase& _case, int _direction)
{
	int nb = 0;
	while (GET_ALIGN_ALLY(_case) & _direction)
		nb++;
	return (nb);
}

static int		countAlignedEnnemy(BoardCase& _case, int _direction)
{
	int nb = 0;
	while (GET_ALIGN_ENMY(_case) & _direction)
		nb++;
	return (nb);
}

void			MinMax::CountNAlignedPieces(const int & n, int & Iapieces, int & Ennemypieces, BoardCase& _case) const
{
	int nbDirections = 8;

	for (int i = 0; i < nbDirections; i++)
	{
		int allyDirection = Board::ConvertDirectionToAlly(i + 1);
		int ennmyyDirection = Board::ConvertDirectionToEnnemy(i + 1);

		Iapieces += countAlignedAlly(_case, allyDirection);
		Ennemypieces += countAlignedEnnemy(_case, ennmyyDirection);
	}
	std::cout << "Ally count: " << Iapieces << std::endl;
	std::cout << "Ennemy count: " << Ennemypieces << std::endl;
}
void			MinMax::CountTotalPieces(int & nb) const
{
	nb = 0;
	BoardCase** cases = Gomoku::Instance().Board.getCases();
	for(unsigned int i = 0; i < Board::HEIGHT; ++i)
	{
		for(unsigned int j = 0; j < Board::WIDTH; ++j)
		{
			if (GET_COLOR(cases[i][j]) != COLOR_NONE) ++nb;
		}
	}
}

int				MinMax::Winner() const
{
	/*int n = 5, iapieces = 0, ennemypieces = 0;
	BoardCase** cases = Gomoku::Instance().Board.getCases();

	this->CountNAlignedPieces(n, iapieces, ennemypieces);
	if (iapieces > 0) return (IA);
	else if (ennemypieces > 0) return (ENNEMY);
	else 
	{
		for(unsigned int i = 0; i < Board::HEIGHT; ++i)
		{
			for(unsigned int j = 0; j < Board::WIDTH; ++j)
			{
				if (cases[i][j] == COLOR_NONE) return (NOBODY_PARTYCONTINUE);
			}
		}
	}*/
	return (NOBODY_PARTYCONTINUE);//NOBODY_PARTYISOVER);
}
int				MinMax::Eval(BoardCase& _case) const
{
	int			n = 5, iapieces = 0, ennemypieces = 0, nb = 0;
	int			winner = this->Winner();
	
	this->CountTotalPieces(nb);
	if(winner != NOBODY_PARTYCONTINUE)
	{
		if (winner == IA) return (MAXIMUM - nb);
		else if (winner == ENNEMY) return (MINIMUM + nb);
		else return (EQUALITY);
	}
	this->CountNAlignedPieces(n, iapieces, ennemypieces, _case);
	return (iapieces - ennemypieces);
}


